简体   繁体   中英

Have you ever restricted yourself to using a subset of language features?

Have you ever restricted yourself to using a subset of language features, and more importantly, why?

I'm curious to find out who choose to use only certain language features and avoid others in order to win big in areas such as, but not limited to, memory usage, execution speed or plain old readability and maintainability. And by doing so did it yield the expected results or did it perhaps just hamper some other aspect of producing software. Are there any cautionary tales or wild success stories out there worth sharing regarding this subject?

Douglas Crockford's book JavaScript: The Good Parts is a prime example of this. He lists 'features' in JavaScript that should be avoided and provides alternatives that use the 'good parts' of the language.

A few of the bad parts are:

  • eval
    slower, harder to read, dangerously insecure

  • ==
    confusing and ambiguous with differently typed operands

  • with
    unpredictable results

Most people program subconciously in an informal subset of the their language of choice that they are comfortable with. For example, my first reaction on being presented with a C++ vector that needs iterating over is to reach for a for-loop, rather than write a predicate and use a standard library algorithm. Possibly a failing on my part, but at least I know the algorithm is there if I really need it.

The last time I can remember conciously writing in a subset language was back in the 80s when most of my target platforms supported FORTRAN 77, but one didn't properly, so I had to write in a FORTRAN 77/FORTRAN IV hybrid. It was a pain - things have got a lot better in recent years, thanks mostly to the FOSS movement.

Yes, all the time.

Because I use Perl, and most people agree that many of our languages features are best not used unless you really need to and you know what you are doing. For example, symbolic references are supported, but you shouldn't use them. goto exists, but you shouldn't use it. You can re-use variable labels as different types, eg $var , @var , %var , but you shouldn't do that, either. You can not use strict to have undeclared variables become symbol table entries automatically, but you really shouldn't do that.

The main reason is that many such features have consequences both obvious and esoteric that can introduce subtle and difficult-to-debug errors into your program if used carelessly. Perl makes lots of things possible and it can be attractive to use certain unusual language features to save a few minutes of coding. There are of course times when esoteric features are handy, and it's great that they are there for you to take advantage of in Perl, as opposed to being absent entirely. But it takes experience to know when that savings is worthwhile, because the vast majority of the time you are just creating a maintenance nightmare for yourself and others down the road.

I am fond of saying TMTOWTDI, BMOTWAW; There's more than one way to do it, but most of those ways are wrong.

It's perfectly possible to create large, literate, maintainable Perl applications. And a good part of doing so is restricting yourself to a subset of language features.

One case is when you're writing a compiler of a new language in itself. You can:

  • Use another language to write a simple compiler for a subset of the new language.
  • Use that subset of the new language to write the compiler for the complete version of itself.

Although PHP was originally a template language, it has grown into a full-fledged OO programming language. For this reason, some say that it is no longer suitable to use as a template language.

Really, though, it's just a matter of discipline. When creating HTML/PHP templates, I restrict myself to the simplest subset possible: conditions and loops and no business logic whatsoever. No object instantiation. No function definitions. More complex logic is separated into other files.

In .NET, we have an app that MUST run on Windows 98, so we are limited to the 2.0 framework, since newer versions don't run on this OS.. That's just sad. Can't use LINQ, Extensions Methods and stuff.

我避免GOTO在某些圈子里被认为是有害的。

It makes sense to not use features your co-developers do not understand. In c++ that goes for most of the language :), but c# also has interesting constructs. Older languages like Delphi might still contain goto. I tend to avoid all templates and XML, as I've found them impossible to DRY

you certainly do that when you code c/c++ code to work both on linux and windows - so you restrict yourself to ANSI c/c++, so I guess multiplatform support is one of the reasons.

other reasons - if you want maximum compatibility with wide spread software/os (like winXP, IE 6.0 ) - then you target your software to those apps/os (like dot net framework 2.0 and not 3.5 and Ie 6 and not ie.8) - to have better compatibility with old uses.

same goes to old hardware compatibility / old graphics device compatibility ect...

Plenty of times. Main reason for me is cross-platform compatibility. Examples:

1) (ages ago) templates were struck out from my company's coding standard as they were too non-standard across the range of compilers we had to support

2) use of exceptions/rtti for c++ - a no-no if you're targetting an embedded platform as well as desktop ones (disclaimer - haven't done any of this in years, so maybe it's more acceptable now though I doubt it)

3) .NET remoting if you're writing an app for .NET desktop and for WinCE - major headache right now :-(

Did not use some .NET features in a portal project which would have issues when running in partially trusted environments because we had to make sure that clients could deploy the solution on servers with assemblies having weak trust policies.

The thing that hurt most was no reflection could be used!

In many cases, you do that unconsciously - you use the subset you know and leave out the unknown features. In other cases, there is more than one way to do it - and you choose to stick to one way all the time, because it makes a program easier to read when it uses less language features. (Especially when "the other way" has no particular advantage - eg it's just here to please people coming from a different language)

Yes.

C++ is such a large, complex language, it is hard to hire a team that can use every feature in its full complexity. I write style guidelines that point engineers to use certain features and avoid others. It's distressing to have engineers stuck on a bug, and have them tell you they never did know what a certain construct meant. Bad engineer? Maybe, but we have to work in reality.

As people have mentioned, languages like Javascript have some features that can get you in trouble, so it's best to avoid them.

Both of these, and other mature languages like PHP and Ruby, have features from many different paradigms. To use them effectively, you don't necessarily avoid certain features, but reach an agreement on how you are going to use the vast set of tools you have available.

I feel a little differently about Java. It is a much simpler language and I think it is realistic to expect engineers to know the entire language. You do sometimes avoid certain features for backward compatibility, but otherwise I want engineers to know and use all of Java.

我计划在接下来的几周内将Lua移植到DLR。

Lotus IBM introduced the getAllEntriesByKey method of the NotesView class in LotusScript R5, I didn't really start using it through unfamiliarity until a couple of years ago, now its a staple part of my programming as an alternative to getAllDocumentsByKey.

There is nothing wrong with getAllDocumentsByKey and I use it all the time but if the view your looking at has hundreds or even thousands of records (documents to a Notes Developer) then scanning the collection you get back can be very slow. If however the document value is a view column entry then scanning the viewEntryCollection you get back from getAllEntriuesByKey is way faster, doesn't make the older code wrong or even unusable, you just need to know when to use each one.

Last week I recoded a process that had to iterate through a collection that turned out could contain anywhere between 0 and 22,000 entries, for 200 records it took 60 seconds to run. The new code finished in 2 seconds (I added temporary timing code) and more importantly took the same amount of time for 500 documents, its a major win for ten minutes of work including unit testing. The method was was available to the developers years ago when they wrote the sub, but they either didn't know about it or more likely had no confidence/ did not understand the performance implications.

We can only use what we are familiar with and have confidence in. The more development work you do the more likely it is that you will widen your experience and be able to use more features of a language to deliver quality software to your customers.

We use XSLT heavily for many of our components. Most of the components are old) uses old parsers, which does not support XSLT 2.0, so we are still using XSLT 1.0 functions even though XSLT 2.0 provides many good functions.

Obviously, if features are deprecated, it's a good idea to avoid them, even if they're technically available.

But also, if you're going to be distributing interpreted scripts to run on a mix of machines, I'll often avoid brand new features so I don't force people to upgrade PHP / Perl / whatever just to be able to run it.

In Verilog and VHDL (programming languages used to design chips), we always have to use the subsets that are "synthesizable" when designing the chip. The whole language can be used for test benches (unit tests).

While not strictly a "language feature" - one construct I avoid in C# is lock(this)

It's a leading cause of deadlock conditions in multi-threaded code since anyone can lock on the same reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM